#include "DatagramSocketChannel.h"
#include <cerrno>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include "EventLoop.h"
#include "Manager.h"
#include "MessageHeader.h"
#include "PlatLogger.h"
#include "SocketOpt.h"
#include "Util.h"
#include "XnccType.h"

namespace xncc {
namespace foundation {

    DatagramSocketChannel::DatagramSocketChannel(EventLoop* loop, int sock_fd, types::connection_id_t connId)
        : Channel(loop, sock_fd, connId), HEADER_LEN(static_cast<int32_t>(sizeof(msg::Header)))
    {
        TRACE_INFO << "create DatagramSocketChannel bind loop id:" << loop->id() << " fd:" << sock_fd
                   << " loop type:" << types::IO_MULTI_MODE::toString(loop->mode());
    }

    DatagramSocketChannel::~DatagramSocketChannel() { ::close(fd()); }

    void DatagramSocketChannel::handleWrite() {}

    void DatagramSocketChannel::handleError(const std::string& reason)
    {
        TRACE_ERROR << "ICMP ERROR Port Unreachable, connid:"_s << fd();
        handleClose(reason);
    }

    void DatagramSocketChannel::sendMsg(const char* msg, size_t len)
    {  // UDP没有写缓冲 直接写即可
        ssize_t writen = ::write(fd(), msg, len);
        if (writen != static_cast<ssize_t>(len)) {
            SYSTEM_ERROR << "write msg failed"_s;
            handleClose(shared::getDisconnectedReason(errno));
        }
    }

    /// 收到消息之后，就是构建消息，然后投递到订阅消息的线程
    void DatagramSocketChannel::handleRead()
    {
        char    buf[65536] = {0};
        ssize_t n          = ::read(fd(), buf, sizeof(buf));
        if (n > 0) {
            for (ssize_t i = 0; i < n;) {
                auto     tmpReadableLen = static_cast<uint32_t>(n - i);
                auto     header         = msg::MessageHeader::decode(buf + i, static_cast<uint32_t>(tmpReadableLen));
                uint32_t msgTotalLen    = header.bodyLen + HEADER_LEN;
                if (tmpReadableLen < msgTotalLen) {
                    break;
                }
                if (header.id >= shared::InnerMsgId::MAX_INNER_MSG_ID) {
                    QUEUE_MGR.pubIPCDataToBusiThread(buf + i + sizeof(header), header.bodyLen, header.id, loopId(),
                                                     connId());
                }
                else {
                    TRACE_ERROR << "trans error msg id:"_s << header.id << " connid:"_s << connId();
                }
                i += msgTotalLen;
            }
        }
        else if (n == 0) {
            handleClose(shared::getDisconnectedReason(0));
        }
        else {
            auto savedErrno = errno;
            if (savedErrno != EINTR && savedErrno != EAGAIN && savedErrno != EWOULDBLOCK) {
                SYSTEM_ERROR << "Connection::handleRead loop id:"_s << loopId();
                handleError(shared::getDisconnectedReason(errno));
            }
        }
    }
}  // namespace foundation
}  // namespace xncc